package crawler.web.other;

import java.util.List;

import library.Tracer;

import org.apache.commons.lang.StringUtils;
import org.htmlparser.Node;
import org.htmlparser.nodes.RemarkNode;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.nodes.TextNode;
import org.htmlparser.tags.Div;
import org.htmlparser.tags.ImageTag;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.tags.MetaTag;
import org.htmlparser.tags.ParagraphTag;
import org.htmlparser.tags.ScriptTag;
import org.htmlparser.tags.SelectTag;
import org.htmlparser.tags.Span;
import org.htmlparser.tags.StyleTag;
import org.htmlparser.tags.TableColumn;
import org.htmlparser.tags.TableHeader;
import org.htmlparser.tags.TableRow;
import org.htmlparser.tags.TableTag;
import org.htmlparser.tags.TitleTag;
import org.htmlparser.util.NodeIterator;
import org.htmlparser.util.NodeList;

import crawler.web.beans.CrawlPageContext;

/**
 * 正文抽取主程序
 * 
 * @author waynechen
 * 
 */
public class ExtractContext {
	/**
	 * 行开始
	 */
	private static final String lineStart = "";
	/**
	 * 行结束
	 */
	private static final String lineEnd = System.getProperty("line.separator");
	/**
	 * 换行符长度
	 */
	private static final int lineSign_size = lineEnd.length();

	/**
	 * 递归钻取正文信息
	 * 
	 * @param root
	 *            被扩展的节点
	 * @param siteUrl
	 *            网站的域名
	 * @return
	 */
	public static void extractHtml(Node root, CrawlPageContext context, String siteUrl) throws Exception {
		// 准备 遍历 子节点
		NodeList subNodes = root.getChildren();
		// -------------------------------root没有子节点-------------------------------
		// 加上结尾标记
		if ((subNodes == null) || (subNodes.size() == 0)) {
			//在没有子节点的情况下, 只收集 <P>节点
			if (root instanceof ParagraphTag) {
				//				StringBuilder temp = new StringBuilder();
				//				context.getList().add(temp);
				//				temp = new StringBuilder();
				//				temp.append(lineEnd);
				//				context.getList().add(temp);
			}
			return;
		}
		// -------------------------------对于root为 p标签 使用extractParagraph进一步抽取-------------------------------
		if (root instanceof ParagraphTag) {
			// 本<p>标签中有子节点
			StringBuilder temp = new StringBuilder();
			//			context.getList().add(temp);
			//抽取<p>标签
			//			extractParagraph(root, siteUrl, context.getList());
			temp = new StringBuilder();
			temp.append(lineEnd);
			//			context.getList().add(temp);
			return;
		}
		// -------------------------------对于 table或者div 标签  设置 bl为true-------------------------------
		// 在最后进行特殊处理
		// 对于<table> <div> 设置bl为true
		boolean bl = false;
		if ((root instanceof TableTag) || (root instanceof Div)) {
			bl = true;
		}
		//-------------------------------对于 非 p, table, dev节点-------------------------------
		// 进行下面处理
		// tableList 收集 遍历到 的 <a> <img>
		try {
			for (NodeIterator e = subNodes.elements(); e.hasMoreNodes();) {
				Node node = (Node) e.nextNode();
				//如果是 a 标签
				if (node instanceof LinkTag) {
					//					context.getList().add(node);
					//设置图片地址
					setLinkImg(node, siteUrl);
				}
				//注释节点
				else if (node instanceof RemarkNode) {
				}
				//如果是 text节点
				else if (node instanceof TextNode) {
					//如果节点有内容
					//					if (node.getText().trim().length() > 0) {
					//						StringBuilder temp = new StringBuilder();
					//						String text = collapse(node.getText());
					//						if (StringUtils.isNotBlank(text)) {
					//							temp.append(text.trim());
					//							tableList.add(temp);
					//						}
					//					}
				}
				//如果 script , style , select 标签
				// ...
				else if (node instanceof ScriptTag || node instanceof StyleTag || node instanceof SelectTag) {
				}
				//如果是 <title>
				else if (node instanceof TitleTag) {
					String text = collapse(node.getText());
					if (StringUtils.isNotBlank(text)) {
						StringBuilder temp = new StringBuilder();
						temp.append(text.trim());
						//						context.getList().add(temp);
					}
				}
				//如果是 img 标签 
				else if (node instanceof ImageTag) {
					ImageTag img = (ImageTag) node;
					//如果 img url 中不包含'http://'
					if (img.getImageURL().toLowerCase().indexOf("http://") < 0) {
						//拼装成 一下 完成的 url地址
						img.setImageURL(siteUrl + img.getImageURL());
					} else {
						//如果 包含 'http://' 说明 已经是一个完整的url地址
						img.setImageURL(img.getImageURL());
					}
					//					context.getList().add(node);
				}
				//如果是 meta 元数据节点
				else if (node instanceof MetaTag) {
					//					parseMetaTag(context, (MetaTag) node);
				}
				//最后处理其它节点
				else {
					//如果是 table节点或者div节点
					if (node instanceof TableTag || node instanceof Div) {
						//如果是节点, 则看是不是有效的table如果不是, 则跳过
						//如果是, 则加入tableList
						TableValid tableValid = new TableValid();
						//判断 table 是不是有效的
						isValidTable(node, tableValid);
						//如果 node 是表单, tr 数会大于2
						if (tableValid.getTrnum() > 2) {
							//							context.getList().add(node);
							continue;
						}
					}
					//剩下的其它节点
					extractHtml(node, context, siteUrl);
					//					if ((context.getList() != null) && (context.getList().size() > 0)) {
					//						Iterator<Object> ti = context.getList().iterator();
					//						while (ti.hasNext()) {
					//							context.getList().add(ti.next());
					//						}
					//					}
				}
			}
		} catch (Exception e) {
			return;
		}

		// 这里主要对上面的代码中, 收集的
		//对 url js  div img 进行处理
		//		if ((context.getList() != null) && (context.getList().size() > 0)) {
		//			if (bl) {
		//				StringBuilder temp = new StringBuilder();
		//				StringBuilder node;
		//				Iterator<Object> ti = context.getList().iterator();
		//				int wordSize = 0;
		//				int status = 0;
		//				while (ti.hasNext()) {
		//					Object k = ti.next();
		//					if (k instanceof LinkTag) {
		//						LinkTag linkTag = (LinkTag) k;
		//						String urlstr = getSiteDomainURL(linkTag.getLink());
		//						if (StringUtils.isNotBlank(urlstr)) {
		//							CrawlURL url = new CrawlURL(linkTag.getLink());
		//							url.setTitle(collapse(linkTag.getLinkText()));
		//							context.getUrlList().add(url);
		//						}
		//						if (status == 0) {
		//							temp.append(lineStart);
		//							status = 1;
		//						}
		//						String link = linkTag.toHtml();
		//						node = new StringBuilder(link);
		//						temp.append(node);
		//					} else if (k instanceof ImageTag) {
		//						if (status == 0) {
		//							temp.append(lineStart);
		//							status = 1;
		//						}
		//						node = new StringBuilder(((ImageTag) k).toHtml());
		//						temp.append(node);
		//					} else if (k instanceof TableTag) {
		//						if (status == 0) {
		//							temp.append(lineStart);
		//							status = 1;
		//						}
		//
		//						node = new StringBuilder(((TableTag) k).toHtml());
		//						temp.append(node);
		//					} else if (k instanceof Div) {
		//						if (status == 0) {
		//							temp.append(lineStart);
		//							status = 1;
		//						}
		//						node = new StringBuilder(((Div) k).toHtml());
		//						temp.append(node);
		//					} else {
		//						node = (StringBuilder) k;
		//						if (status == 0) {
		//							if (node.indexOf("<p") < 0) {
		//								temp.append(lineStart);
		//								temp.append(node);
		//								wordSize = wordSize + node.length();
		//								status = 1;
		//							} else {
		//								temp.append(node);
		//								status = 1;
		//							}
		//						} else if (status == 1) {
		//							if (node.indexOf("</p") < 0) {
		//								if (node.indexOf("<p") < 0) {
		//									temp.append(node);
		//									wordSize = wordSize + node.length();
		//								} else {
		//									temp.append(lineEnd);
		//									temp.append(node);
		//									status = 1;
		//								}
		//							} else {
		//								temp.append(node);
		//								status = 0;
		//							}
		//						}
		//					}
		//				}
		//				if (status == 1) {
		//					temp.append(lineEnd);
		//				}
		//
		////				if (wordSize > context.getNumber()) {
		////					context.setNumber(wordSize);
		////					context.setTextBuffer(temp);
		////				}
		//				return;
		//			} else {
		//				return;
		//			}
		//		}
		return;
	}

	//	public static void parseMetaTag(CrawlPageContext context, MetaTag node) {
	//		String name = node.getAttribute("name");
	//		if (StringUtils.isNotBlank(name)) {
	//			String content = node.getAttribute("content");
	//			if (name.equals("keywords") || name.equals("title"))
	//				context.setKeywords(content);
	//			else if (name.equals("description")) {
	//				context.setDescription(content);
	//			}
	//		}
	//	}

	//	/**
	//	 * 压缩字符串空格
	//	 * 
	//	 * @author waynechen
	//	 * @param title
	//	 * @return
	//	 */
	//	private static String compressLinkText(String title) {
	//		return title.trim().replaceAll("\\s", "");
	//	}

	/**
	 * 钻取段落中的内容
	 * 
	 * @param root
	 * @param siteUrl
	 * @param tableList
	 * @return
	 */
	private static List<Object> extractParagraph(Node root, String siteUrl, List<Object> tableList) {
		NodeList nodeList = root.getChildren();
		// --------------------如果没有子节点------------------
		if ((nodeList == null) || (nodeList.size() == 0)) {
			//如果 root 是段落 节点
			if (root instanceof ParagraphTag) {
				StringBuilder temp = new StringBuilder();
				temp.append(lineEnd);
				tableList.add(temp);
				return tableList;
			}
			return null;
		}
		try {
			// 对于 所有 子节点
			for (NodeIterator e = nodeList.elements(); e.hasMoreNodes();) {
				Node node = (Node) e.nextNode();
				// 脚本节点
				if (node instanceof ScriptTag || node instanceof StyleTag || node instanceof SelectTag) {
				}
				// 链接节点
				else if (node instanceof LinkTag) {
					tableList.add(node);
					//补全子节点的主机地址
					setLinkImg(node, siteUrl);
				}
				// 对于 img 标签 补全 主机域名
				else if (node instanceof ImageTag) {
					ImageTag img = (ImageTag) node;
					if (img.getImageURL().toLowerCase().indexOf("http://") < 0) {
						img.setImageURL(siteUrl + img.getImageURL());
					} else {
						img.setImageURL(img.getImageURL());
					}
					tableList.add(node);
				}
				// 对于 内部 文本 节点
				else if (node instanceof TextNode) {
					//					if (node.getText().trim().length() > 0) {
					//						//去除无效字符
					//						String text = collapse(node.getText());
					//						StringBuilder temp = new StringBuilder();
					//						temp.append(text);
					//						tableList.add(temp);
					//					}
				}
				// 对于 <span> 节点
				else if (node instanceof Span) {
					StringBuilder spanWord = new StringBuilder();
					getSpanWord(node, spanWord);
					if ((spanWord.length() > 0)) {
						//去除无效字符
						String text = collapse(node.getText());
						StringBuilder temp = new StringBuilder();
						temp.append(text);
						tableList.add(temp);
					}
				}
				//
				else if (node instanceof TagNode) {
					String tag = node.toHtml();
					if (tag.length() <= 10) {
						tag = tag.toLowerCase();
						if ((tag.indexOf("strong") >= 0) || (tag.indexOf("b") >= 0)) {
							StringBuilder temp = new StringBuilder();
							temp.append(tag);
							tableList.add(temp);
						}
					} else {
						if (node instanceof TableTag || node instanceof Div) {
							TableValid tableValid = new TableValid();
							isValidTable(node, tableValid);
							if (tableValid.getTrnum() > 2) {
								tableList.add(node);
								continue;
							}
						}
						extractParagraph(node, siteUrl, tableList);
					}
				}
			}
		} catch (Exception e) {
			Tracer.exception(e);
			return null;
		}
		return tableList;
	}

	//	private static Pattern urlPattern = Pattern.compile("(http://[^/]*?" + "/)(.*?)", Pattern.CASE_INSENSITIVE + Pattern.DOTALL);

	//	/**
	//	 * 获取域名<br>
	//	 * 从一个字符串中提取出链接
	//	 */
	//	public static String getSiteDomainURL(String link) {
	//		Matcher matcher = urlPattern.matcher(link);
	//		String url = "";
	//		while (matcher.find()) {
	//			int start = matcher.start(1);
	//			int end = matcher.end(1);
	//			url = link.substring(start, end - 1).trim();
	//		}
	//		return url;
	//	}

	/**
	 * 获得 <span> 之间的
	 * 
	 * @author waynechen
	 * @param nodeP
	 * @param spanWord
	 */
	private static void getSpanWord(Node nodeP, StringBuilder spanWord) {
		NodeList nodeList = nodeP.getChildren();
		try {
			for (NodeIterator e = nodeList.elements(); e.hasMoreNodes();) {
				Node node = (Node) e.nextNode();
				if (node instanceof ScriptTag || node instanceof StyleTag || node instanceof SelectTag) {
				}
				// 对于 textnode 直接获得其值
				else if (node instanceof TextNode) {
					spanWord.append(node.getText());
				}
				// <span> 标签 , 递归
				else if (node instanceof Span || node instanceof ParagraphTag) {
					getSpanWord(node, spanWord);
				}
				// 对于小的标签, 直接获取其中 html
				else if (node instanceof TagNode) {
					String tag = node.toHtml().toLowerCase();
					if (tag.length() <= 10) {
						if ((tag.indexOf("strong") >= 0) || (tag.indexOf("b") >= 0)) {
							spanWord.append(tag);
						}
					}
				}
			}
		} catch (Exception e) {
			Tracer.exception(e);
		}
		return;
	}

	/**
	 * 除去无效字符
	 * 
	 * @author waynechen
	 * @param string
	 * @return
	 */
	public static String collapse(String string) {
		string = string.replaceAll("&nbsp;", "").replaceAll("\\s", "");
		int chars;
		int length;
		int state;
		char character;
		StringBuilder buffer = new StringBuilder();
		chars = string.length();
		if (0 != chars) {
			length = buffer.length();
			state = ((0 == length) || (buffer.charAt(length - 1) == ' ') || //
			((lineSign_size <= length) && buffer.substring(length - lineSign_size, length).equals(lineEnd))) ? 0 : 1;

			for (int i = 0; i < chars; i++) {
				character = string.charAt(i);
				switch (character) {
				case '\u0020':
				case '\u0009':
				case '\u000C':
				case '\u200B':
				case '\u00a0':
				case '\r':
				case '\n':
					if (0 != state) {
						state = 1;
					}
					break;
				default:
					if (1 == state) {
						buffer.append(' ');
					}
					state = 2;
					buffer.append(character);
				}
			}
		}
		return buffer.toString().trim();
	}

	/**
	 * 设置图象连接, 补全, 主机域名
	 * 
	 * @param root
	 * @param siteUrl
	 */
	private static void setLinkImg(Node root, String siteUrl) {
		NodeList nodeList = root.getChildren();
		try {
			//遍历
			// 保存link的图片
			// 网页中点击图片则去往link所指的页面
			for (NodeIterator e = nodeList.elements(); e.hasMoreNodes();) {
				Node node = (Node) e.nextNode();
				if (node instanceof ImageTag) {
					ImageTag img = (ImageTag) node;
					if (img.getImageURL().toLowerCase().indexOf("http://") < 0) {
						img.setImageURL(siteUrl + img.getImageURL());
					} else {
						img.setImageURL(img.getImageURL());
					}
				}
			}
		} catch (Exception e) {
			return;
		}
		return;
	}

	/**
	 * 判断TABLE是否是表单
	 * 
	 * @param nodeP
	 * @return
	 */
	private static void isValidTable(Node nodeP, TableValid tableValid) {
		NodeList nodeList = nodeP.getChildren();
		// 如果该表单没有子节点则返回
		if ((nodeList == null) || (nodeList.size() == 0)) {
			return;
		}
		try {
			//遍历 所有子节点 
			for (NodeIterator e = nodeList.elements(); e.hasMoreNodes();) {
				Node node = (Node) e.nextNode();
				// 如果子节点本身也是表单则返回
				if (node instanceof TableTag || node instanceof Div) {
					return;
				}
				//如果 是 script style select节点则返回
				else if (node instanceof ScriptTag || node instanceof StyleTag || node instanceof SelectTag) {
					return;
				}
				//如果是 TD节点
				else if (node instanceof TableColumn) {
					return;
				}
				//如果是 tr节点
				else if (node instanceof TableRow) {
					TableColumnValid tcValid = new TableColumnValid();
					tcValid.setValid(true);
					//判断tr的有效性, 通过 tc来判断
					findTD(node, tcValid);
					//如果tc是有效的
					if (tcValid.isValid()) {
						//如果tc的td数小于2
						if (tcValid.getTdNum() < 2) {
							//
							if (tableValid.getTdnum() > 0) {
								return;
							} else {
								continue;
							}
						}
						//如果tc的td数大于等于2
						else {
							if (tableValid.getTdnum() == 0) {
								tableValid.setTdnum(tcValid.getTdNum());
								tableValid.setTrnum(tableValid.getTrnum() + 1);
							} else {
								if (tableValid.getTdnum() == tcValid.getTdNum()) {
									tableValid.setTrnum(tableValid.getTrnum() + 1);
								} else {
									return;
								}
							}
						}
					}
				} else {
					isValidTable(node, tableValid);
				}
			}
		} catch (Exception e) {
			return;
		}
		return;
	}

	/**
	 * 判断是否有效TR
	 * 
	 * @param nodeP
	 * @param TcValid
	 * @return
	 */
	private static void findTD(Node nodeP, TableColumnValid tcValid) {
		NodeList nodeList = nodeP.getChildren();
		// 如果该表单没有子节点则返回
		if ((nodeList == null) || (nodeList.size() == 0)) {
			return;
		}
		try {
			for (NodeIterator e = nodeList.elements(); e.hasMoreNodes();) {
				Node node = (Node) e.nextNode();
				//  如果有嵌套表单 
				// 如果有 table , div , tr , th
				// 则不是有效的 tr 
				if (node instanceof TableTag || node instanceof Div || node instanceof TableRow || node instanceof TableHeader) {
					tcValid.setValid(false);
					return;
				}
				//如果是 script style select 也不是有效的 tr
				else if (node instanceof ScriptTag || node instanceof StyleTag || node instanceof SelectTag) {
					tcValid.setValid(false);
					return;
				}
				// 如果是 td(表的列)
				else if (node instanceof TableColumn) {
					// 表的列加1
					tcValid.setTdNum(tcValid.getTdNum() + 1);
				}
				//其它的节点则继续递归查找
				else {
					findTD(node, tcValid);
				}
			}
		} catch (Exception e) {
			tcValid.setValid(false);
			return;
		}
		return;
	}
}

//public static void main(String[] args) {
//		LinkBean c = new LinkBean();
//		c.setEncode("gb2312");
//		c.setLink("https://www.google.com/webhp?hl=en&tab=ww");
//		c.setLinktext("testsetLinktextsetLinktextsetLinktext");
//		ExtractContext.makeContext(c);
//	}

//	/**
//	 * 收集HTML页面信息<br>
//	 * 根据模板文件, 整理后保存到文件
//	 * 
//	 * @param url
//	 * @param urlEncode
//	 */
//	public static void makeContext(LinkBean linkBean) {
//		//		String metakeywords = "<META content={0} name=keywords>";
//		String metatitle = "<TITLE>{0}</TITLE>";
//		String metadesc = "<META content={0} name=description>";
//		String netshot = "<p> 正文快照: 时间{0}</p> ";
//
//		String tempLeate = "<LI class=active><A href=\"{0}\" target=_blank>{1}</A></LI>";
//		String crop = "<p><A href=\"{0}\" target=_blank>{1}</A></p> ";
//
//		try {
//			String siteDomainURL = getLinkUrl(linkBean.getLink());
//			Parser parser = new Parser(linkBean.getLink());
//			parser.setEncoding(linkBean.getEncode());
//			//分析所有节点
//			for (NodeIterator e = parser.elements(); e.hasMoreNodes();) {
//				Node node = (Node) e.nextNode();
//				//处理html节点
//				if (node instanceof Html) {
//					PageContext context = new PageContext();
//					context.setNumber(0);
//					context.setTextBuffer(new StringBuilder());
//					// 抓取出内容
//					// note -> context
//					extractHtml(node, context, siteDomainURL);
//
//					//--------------跟上面没有 关系-------------
//					//模板
//					String srcfilePath = "config/context.vm";
//					//整理后的输出路径
//					String destfilePath = "source/extractHtml.txt";
//					BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(srcfilePath), "gbk"));
//					BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destfilePath), "gbk"));
//					String lineContext = context.getTextBuffer().toString();
//					String line;
//					while ((line = reader.readLine()) != null) {
//						int start = line.indexOf("#context");
//						if (start >= 0) {
//							String tempCrop = StringUtils.replace(crop, "{0}", linkBean.getLink());
//							tempCrop = StringUtils.replace(tempCrop, "{1}", "      原文链接： " + linkBean.getLink());
//							writer.write(tempCrop + lineSign);
//							writer.write(netshot + lineSign);
//							writer.write(lineContext + lineSign);
//							continue;
//						}
//						int start1 = line.indexOf("#titledesc");
//						if (start1 >= 0) {
//							String tempLine = StringUtils.replace(tempLeate, "{0}", "test.htm");
//							tempLine = StringUtils.replace(tempLine, "{1}", "标题:  " + linkBean.getLinktext());
//							writer.write(tempLine + lineSign);
//							continue;
//						}
//						int start2 = line.indexOf("#metatitle");
//						if (start2 >= 0) {
//							metatitle = StringUtils.replace(metatitle, "{0}", linkBean.getLinktext());
//							writer.write(metatitle + lineSign);
//							continue;
//						}
//						int start3 = line.indexOf("#metadesc");
//						if (start3 >= 0) {
//							metadesc = StringUtils.replace(metadesc, "{0}", linkBean.getLinktext());
//							writer.write(metadesc + lineSign);
//							continue;
//						}
//						writer.write(line + lineSign);
//					}
//					writer.flush();
//					writer.close();
//					reader.close();
//				}
//			}
//		} catch (Exception e) {
//			System.out.println(e);
//		}
//	}
